// 使用互斥锁
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>

std::mutex mtx;

void thread_function(int i)
{
    std::cout << "Thread " << i << " is going to lock" << std::endl;
    std::lock_guard<std::mutex> lock(mtx);
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    std::cout << "Thread " << std::this_thread::get_id() << " is running" << std::endl;
}

struct Complex
{
    std::mutex mutex;
    int i;

    Complex() : i(0) {}

    void mul(int x)
    {
        std::lock_guard<std::mutex> lock(mutex);
        i *= x;
    }

    void div(int x)
    {
        std::lock_guard<std::mutex> lock(mutex);
        i /= x;
    }

    void both(int x, int y)
    {
        // 同一个锁枷锁了两次 注意通过别的手法可以避免
        std::lock_guard<std::mutex> lock(mutex);
        mul(x);
        div(y);
    }
};

void test1()
{
    std::thread t1(thread_function, 1);
    std::thread t2(thread_function, 2);
    std::thread t3(thread_function, 3);
    t1.join();
    t2.join();
    t3.join();
}

void test2()
{
    Complex complex;
    complex.both(32, 23);
}

// 更换成recursive_mutex

struct Complexrecursive
{
    std::recursive_mutex mutex;
    int i;

    Complexrecursive() : i(0) {}

    void mul(int x)
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);
        i *= x;
    }

    void div(int x)
    {
        std::lock_guard<std::recursive_mutex> lock(mutex);
        i /= x;
    }

    void both(int x, int y)
    {
        // 同一个锁枷锁了两次 注意通过别的手法可以避免
        std::lock_guard<std::recursive_mutex> lock(mutex);
        mul(x);
        div(y);
    }
};

void test3()
{
    Complexrecursive complex;
    complex.both(32, 23);
}
std::timed_mutex mutex;

void work()
{
    std::chrono::milliseconds timeout(130);

    while (true)
    {
        // 获取锁 如果获取不到锁 则等待timeout时间 如果获取到锁 则继续执行
        if (mutex.try_lock_for(timeout))
        {
            std::cout << std::this_thread::get_id() << ": do work with the mutex" << std::endl;

            std::chrono::milliseconds sleepDuration(100);
            std::this_thread::sleep_for(sleepDuration);

            mutex.unlock();
            std::this_thread::sleep_for(sleepDuration);
        }
        else
        {
            std::cout << std::this_thread::get_id() << ": do work without the mutex" << std::endl;

            std::chrono::milliseconds sleepDuration(250);
            std::this_thread::sleep_for(sleepDuration);
        }
    }
}
// 使用timed_mutex
void test4()
{
    std::thread t1(work);
    std::thread t2(work);
    std::thread t3(work);
    std::thread t4(work);
    std::thread t5(work);
    t1.join();
    t2.join();
    t3.join();
    t4.join();
    t5.join();
}
int main()
{
    test4();
    return 0;
}
